#ifndef GRAPH_DISPLAY_H
#define GRAPH_DISPLAY_H

#include "GraphObject.h"
#include "Uncopyable.h"
#include "Color.h"

#include <set>
#include <list>
#include <windows.h>
#include <QtGui/qwidget.h>

class BitmapImage;

namespace GUI
{
	class WidgetBase;

	typedef std::set<GraphObject*> SetOfGraphObjects;
	struct QueueOfGraphObjects : public std::list<GraphObject*>
	{
		void pop()
		{ pop_front(); }
		void push(GraphObject* p)
		{ push_back(p);}
	};

	class GraphDisplay : private Uncopyable
	{
		friend class GraphObject;

	public:
		GraphDisplay();
		virtual ~GraphDisplay();

		//properties
		GraphDisplay& SetContext(const DrawContext& dc)
		{ mContext = dc; Change(); return *this; }
		const GUI::DrawContext& Context() const
		{ return mContext; }

		GraphDisplay& SetColor(RGBColor c)
		{ mColor = c; Invalidate(); return *this; }
		RGBColor Color() const
		{ return mColor; }

		GraphDisplay& ClearClicks()
		{ while(!mObjectsClicked.empty()) mObjectsClicked.pop(); return *this; }
		QueueOfGraphObjects& ObjectsClicked()
		{ return mObjectsClicked; }

	private:
		// Add() and Remove() are only provided for GraphObject self registering
		// and unregistering in the GraphObject constructor and destructor.
		// Calling them from elsewhere will lead to inconsistency between
		// a GraphObject's display reference, and the display it is attached to.
		GraphDisplay& Add(GraphObject* obj);
		GraphDisplay& Remove(GraphObject*);

	public:
		GraphDisplay& DeleteObjects()
		{ while(!mObjectsClicked.empty()) delete *mObjectsClicked.begin(); return *this; }
		// Read bitmap data, resampled to target resolution
		BitmapImage BitmapData(int width = 0, int height = 0) const;

		//Graphics functions
		// Invalidate the display's entire area
		virtual GraphDisplay& Invalidate();
		// Invalidate a rectangle given in pixel coordinates
		virtual GraphDisplay& InvalidateRect(const Rect&);
		// Force immediate redrawing of invalidated window areas
		virtual const GraphDisplay& Update() const;

		// Events
		void Paint(const void* RegionHandle = NULL);
		void Change();
		void Click(int x, int y);

		//coordinate conversion for object drawing
		Rect NormalizedToPixelCoords(const Rect&) const;
		Rect PixelToNormalizedCoords(const Rect&) const;
	private:
		void ClearOffscreenBuffer();
		static void BitmapImageFromQPixmap(BitmapImage&, const QPixmap&);
		DrawContext			mContext;
		RGBColor			mColor;
		SetOfGraphObjects	mObjects;
		QueueOfGraphObjects	mObjectsClicked;
		friend class		GUI::WidgetBase;
		QPixmap*			mOffscreenBmp;
		QRegion				mInvalidRegion;
		QWidget*			mpWidget;
		bool				mUsingGL;
	};
}

#endif